/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.jfonia.view;

import org.jfonia.view.panels.ViewPanel;
import java.awt.Graphics;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import org.jfonia.connect5.basics.BasicValueNode;
import org.jfonia.connect5.basics.MutableValueNode;
import org.jfonia.connect5.intervals.BasicDoubleInterval;
import org.jfonia.connect5.intervals.LinkedDoubleIntervalList;
import org.jfonia.connect5.numerical.UnidirectionalDoubleSumRelation;
import org.jfonia.connect5.relations.Equal;
import org.jfonia.constants.ViewConstants;
import org.jfonia.model.IListObserver;
import org.jfonia.model.Staff;
import org.jfonia.model.StaffCollection;
import org.jfonia.view.labels.Label;
import org.jfonia.view.panels.ViewLayerPanel;
import org.jfonia.view.relations.DoubleInversionRelation;

/**
 *
 * @author Rik Bauwens
 */
public class StaffCollectionView implements IListObserver<Staff>, Iterable<StaffView>
{
        private ViewPanel viewPanel;
        private ViewLayerPanel viewLayerPanel;
        private StaffCollection staffCollection;

        private MutableValueNode<Double> xNode;
        private MutableValueNode<Double> widthNode;
        private RelationBuilder relationBuilder;
        private LinkedDoubleIntervalList yNodes;
        private List<StaffView> staffViews;

        private MutableValueNode<Boolean> staffCollectionSelectionNode;

        public StaffCollectionView(ViewPanel viewPanel, ViewLayerPanel viewLayerPanel,
                                   StaffCollection staffCollection,
                                   MutableValueNode<Double> xNode, MutableValueNode<Double> yNode,
                                   MutableValueNode<Double> widthNode, MutableValueNode<Double> heightNode)
        {
                this.xNode = xNode;
                this.widthNode = widthNode;

                this.viewPanel = viewPanel;
                this.viewLayerPanel = viewLayerPanel;

                staffViews = new LinkedList<StaffView>();
                
                yNodes = new LinkedDoubleIntervalList();
                MutableValueNode<Double> invertedYNode = new BasicValueNode<Double>(0.0);
                new DoubleInversionRelation(yNodes.getBeginNode(), invertedYNode);
                BasicDoubleInterval staffCollectionSpacing = new BasicDoubleInterval();
                new UnidirectionalDoubleSumRelation(yNodes.getEndNode(), invertedYNode,
                                                    staffCollectionSpacing.getBeginNode());
                staffCollectionSpacing.setDifference(ViewConstants.STAFF_COLLECTION_SPACING);
                new Equal<Double>(staffCollectionSpacing.getEndNode(), heightNode);

                BasicDoubleInterval headerInterval = new BasicDoubleInterval();
                yNodes.add(headerInterval);
                relationBuilder = new RelationBuilder(xNode, widthNode, viewPanel, headerInterval, this);

                staffCollectionSelectionNode = new BasicValueNode<Boolean>(false);

                setStaffCollection(staffCollection);
        }

        public boolean hasFocus()
        {
                for(StaffView staffView : staffViews)
                {
                        if(staffView.hasFocus())
                                return true;
                }
                return false;
        }

        public MutableValueNode<Boolean> getStaffCollectionSelectionNode()
        {
                return staffCollectionSelectionNode;
        }

        public StaffView staffViewAbove(StaffView staffView)
        {
                Integer index = staffViews.indexOf(staffView);
                if(index == null || index.intValue() <= 0)
                        return null;
                return staffViews.get(index - 1);
        }

        public StaffView staffViewBelow(StaffView staffView)
        {
                Integer index = staffViews.indexOf(staffView);
                if(index == null || index.intValue() >= staffViews.size() - 1)
                        return null;
                return staffViews.get(index + 1);
        }

        public double getX(int tick)
        {
                return relationBuilder.getX(tick);
        }
        
        public void setBoxPanelSelected(Label label, boolean selected)
        {
                relationBuilder.setBoxPanelSelected(label, selected);
        }

        public StaffCollection getStaffCollection()
        {
                return staffCollection;
        }

        private void setStaffCollection(StaffCollection staffCollection)
        {
                this.staffCollection = staffCollection;                
                staffCollection.addObserver(this);
                Iterator<Staff> it = staffCollection.iterator();
                while(it.hasNext())
                        addStaff(it.next());
        }

        public int getStaffViewlIndex(Staff staff)
        {
                int i = 0;
                while(i < staffViews.size() &&
                      staffViews.get(i).getStaff() != staff)
                        i++;

                if(i < staffViews.size())
                        return i;
                return -1;
        }

        public void addStaff(Staff staff)
        {
                //Only add a staffcollection when no view with the same
                //staffcollection exists already
                if(getStaffViewlIndex(staff) < 0)
                {
                        BasicDoubleInterval yInterval = new BasicDoubleInterval();
                        yNodes.add(yInterval);
                        int index = yNodes.indexOf(yInterval);
                        staffViews.add(index - 1, new StaffView(viewPanel, viewLayerPanel, staff,
                                              relationBuilder, this, yInterval.getBeginNode(),
                                              yInterval.getDifferenceNode()));
                }
        }

        public void removeStaff(Staff staff)
        {
                //Staffcollection can only be removed when there is a view
                //containing it
                int index = getStaffViewlIndex(staff);
                if(index >= 0)
                {
                        yNodes.remove(index);
                        staffViews.remove(index);
                }
        }

        public StaffView previousStaffView(StaffView staffView)
        {
                int index = staffViews.indexOf(staffView);
                if(index > 0)
                            return staffViews.get(index - 1);
                return null;
        }

        public StaffView nextStaffView(StaffView staffView)
        {
                int index = staffViews.indexOf(staffView);
                if(index < staffViews.size() - 1)
                            return staffViews.get(index + 1);
                return null;
        }

        //Staff added to collection
        public void itemAdded(Staff item)
        {
                addStaff(item);
        }

        //Staff removed from collection
        public void itemRemoved(Staff item)
        {
                removeStaff(item);
        }

        public void paintComponent(Graphics g)
        {
                for(StaffView staffView : staffViews)
                        staffView.paintComponent(g);
        }

        public Iterator<StaffView> iterator()
        {
                return staffViews.iterator();
        }
}
